All files / web/src/app/api/curriculum/[playerId]/skills/metrics route.ts

0% Statements 0/61
0% Branches 0/1
0% Functions 0/1
0% Lines 0/61

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62                                                                                                                           
/**
 * API route for skill metrics
 *
 * GET /api/curriculum/[playerId]/skills/metrics
 * Returns computed skill metrics for scoreboard display.
 */

import { NextResponse } from 'next/server'
import { and, desc, eq, inArray } from 'drizzle-orm'
import { db } from '@/db'
import * as schema from '@/db/schema'
import { withAuth } from '@/lib/auth/withAuth'
import { canPerformAction } from '@/lib/classroom'
import { computeStudentSkillMetrics } from '@/lib/curriculum/skill-metrics'
import { getRecentSessionResults } from '@/lib/curriculum/session-planner'
import { getUserId } from '@/lib/viewer'

/**
 * GET /api/curriculum/[playerId]/skills/metrics
 * Get computed skill metrics for a player.
 *
 * These metrics are computed on-the-fly from session results:
 * - Overall mastery (weighted average of pKnown)
 * - Category breakdown (basic, fiveComplements, etc.)
 * - Normalized response time (seconds per term)
 * - Accuracy trends
 * - Progress metrics (improvement rate, streak, problem counts)
 */
export const GET = withAuth(async (_request, { params }) => {
  const { playerId } = (await params) as { playerId: string }

  try {
    // Authorization check
    const userId = await getUserId()
    const canView = await canPerformAction(userId, playerId, 'view')
    if (!canView) {
      return NextResponse.json({ error: 'Not authorized' }, { status: 403 })
    }

    // Get problem results for BKT computation (last 100 sessions for comprehensive history)
    const results = await getRecentSessionResults(playerId, 100)

    // Get session plans for streak calculation
    const sessions = await db.query.sessionPlans.findMany({
      where: and(
        eq(schema.sessionPlans.playerId, playerId),
        inArray(schema.sessionPlans.status, ['completed', 'abandoned'])
      ),
      orderBy: [desc(schema.sessionPlans.completedAt)],
      limit: 100,
    })

    // Compute metrics
    const metrics = computeStudentSkillMetrics(results, sessions)

    return NextResponse.json({ metrics })
  } catch (error) {
    console.error('Error fetching skill metrics:', error)
    return NextResponse.json({ error: 'Failed to fetch skill metrics' }, { status: 500 })
  }
})